package pogvue.io;

import pogvue.datamodel.Alignment;
import pogvue.datamodel.Sequence;
import pogvue.datamodel.SequenceFeature;
import pogvue.datamodel.SequenceI;
import pogvue.gui.AlignmentPanel;
import pogvue.gui.KmerRenderer;
import pogvue.util.Format;

import java.awt.*;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

public class MafFile extends AlignFile {

    private String reforg = null;
    private Vector orgs;
    private Hashtable orgstr;

    public MafFile(SequenceI[] s) {
	super(s);
    }
    
    public MafFile(String inStr) {
	super(inStr);
    }
    
    public void initData() {
	super.initData();
    }
    
    private MafFile(String inFile, String type) throws IOException {
	super(inFile,type);
    }
    
  public void parse()  {
      int prev = 0;

      Hashtable    sfhash;
      StringBuffer refstr = new StringBuffer();

      orgstr = new Hashtable();
      orgs = new Vector();

      try {
      while ((sfhash = get_maf_feat()) != null) {
	  
	  SequenceFeature sf = (SequenceFeature)sfhash.get(reforg);

	  if (sf.getStart() <= prev) {
	      System.err.println("Discarding due to overlap " + sf.getStart() + " " + prev);
	  } else {

	      int newstart = sf.getStart();

	      Enumeration en = sfhash.keys();

	      while (en.hasMoreElements()) {
		  String tmporg = (String)en.nextElement();

		  if (!orgs.contains(tmporg) && !tmporg.equals(reforg)) {
		      orgs.addElement(tmporg);
		      
		      String tmpstr = pad_string('-',refstr.length());

		      orgstr.put(tmporg,new StringBuffer(tmpstr));
		  }
	      }

	      // This is the padding in between pieces.  Should come from a reference sequence

	      refstr.append(pad_string('-',newstart-prev-1));

	      // Add in organism pads

	      for (int i = 0; i < orgs.size(); i++) {
		  String org = (String)orgs.elementAt(i);
		  StringBuffer tmpstr = (StringBuffer)orgstr.get(org);
		      
		  tmpstr.append(pad_string('-',(newstart-prev-1)));

	      }

	      String refaln = sf.getAlignString();

	      char[] refaln_arr = refaln.toCharArray();
	      
	      char[][] aln_arr = new char[orgs.size()][];
		  
	      for (int i = 0; i < orgs.size(); i++) {
		  String org = (String)orgs.elementAt(i);

		  if (sfhash.containsKey(org)) {
		      SequenceFeature tmpsf = (SequenceFeature)sfhash.get(org);

		      String tmpaln = tmpsf.getAlignString();

		      char[] tmparr = tmpaln.toCharArray();

		      aln_arr[i] = tmparr;
		  }
	      }

	      int len;
	      int i = 0;
	      StringBuffer refaln_new = new StringBuffer();

	      // Now only add in non-gap reforg columns

	      while (i < refaln.length()) {

		  for (int ii = 0; ii < orgs.size(); ii++) {
		      String org = (String)orgs.elementAt(ii);

		      if (sfhash.containsKey(org)) {
			  if (refaln_arr[i] != '-') {
			      StringBuffer tmp = (StringBuffer)orgstr.get(org);
			      tmp.append(aln_arr[ii][i]);
			  }
		      }
		  }
		  i++;
	      }

	      i = 0;

	      while (i < refaln.length()) {
		  if (refaln_arr[i] != '-') {
		      refaln_new.append(refaln_arr[i]);
		  }
		  i++;
	      }

	      // Add in pads for orgs not in the alignment
	      for (int ii = 0; ii < orgs.size(); ii++) {
		  String org = (String)orgs.elementAt(ii);

		  if (!sfhash.containsKey(org)) {
		      StringBuffer tmpstr = (StringBuffer)orgstr.get(org);

		      tmpstr.append(pad_string('-',refaln_new.length()));
		  }
	      } 

	      refstr.append(refaln_new);

	      //	      System.err.println(refstr);

	      for (int ii = 0; ii < orgs.size(); ii++) {

		  String org = (String)orgs.elementAt(ii);
		  
		  //		  System.err.println((StringBuffer)orgstr.get(org));
	      }
	      
	      prev = sf.getEnd();
	  }
      }

      seqs = new Vector();

      seqs.addElement(new Sequence(reforg,refstr.toString().toUpperCase(),1,refstr.length()));

      for (int i = 0; i < orgs.size(); i++) {
	  String org = (String)orgs.elementAt(i);
	  String tmpstr = orgstr.get(org).toString();

	  seqs.addElement(new Sequence(org,tmpstr.toUpperCase(),1,refstr.length()));
      }



//       System.out.println(">" + reforg);

      
//       while (refstr.length() > 0) {
// 	  String tmp;

// 	  if (refstr.length() > 72) {
// 	      tmp = refstr.substring(0,72);
// 	      refstr = new StringBuffer(refstr.substring(72));
// 	  } else {
// 	      tmp = refstr.toString();
// 	      refstr = new StringBuffer();
// 	  }

	  

// 	  System.out.println(tmp);
//       }

//       for (int i = 0;i < orgs.size(); i++) {
// 	  String org = (String)orgs.elementAt(i);

// 	  if (!org.equals(reforg)) {
// 	      StringBuffer tmpstr = (StringBuffer)orgstr.get(org);
	      
// 	      System.out.println(">" + org);
	      
// 	      String tmp;
	      
// 	      while (tmpstr.length() > 0) {
// 		  if (tmpstr.length() > 72) {
// 		      tmp = tmpstr.substring(0,72);
// 		      tmpstr = new StringBuffer(tmpstr.substring(72));
// 		  } else {
// 		      tmp = tmpstr.toString();
// 		      tmpstr = new StringBuffer();
// 		  }
		  
		  
		  
// 		  System.out.println(tmp);
// 	      }
// 	  }
//       }
      } catch  (IOException e) {
	  System.out.println("Exception " + e);
      }
  }

    private Hashtable get_maf_feat() throws IOException {
	String line;

	double score;
	Vector orgs = new Vector();
	Hashtable out = new Hashtable();

	while ((line = nextLine()) != null) {
	    if (line.indexOf("a score=") == 0) {

		while ((line = nextLine()) != null && !line.equals("")) {

		    StringTokenizer str = new StringTokenizer(line);
		    
		    SequenceFeature sf = new SequenceFeature();
		    
		    String horg = "";
		    
		    str.nextToken();
		    
		    String name    = str.nextToken();
		    int    start   = Integer.parseInt(str.nextToken());
		    int    len     = Integer.parseInt(str.nextToken());
		    String strand  = str.nextToken();
		    int    srcsize = Integer.parseInt(str.nextToken());
		    String aln     = str.nextToken();
		    
		    if (name.indexOf(".chr") > 0) {
			horg = name.substring(0,name.indexOf(".chr"));
			name = name.substring(name.indexOf(".chr") + 4);
		    }
		    
		    if (reforg == null) {
			reforg = horg;
		    }
		    
		    orgs.addElement(horg);
		    
		    sf.setId(name);
		    sf.setStart(start+1);
		    sf.setEnd(start+len);
		    

		    if (strand.equals("+")) {
			sf.setStrand(1);
		    } else if (strand.equals("-")) {
			sf.setStrand(-1);
		    } else {
			System.out.println("Wrong strand");
		    }
		    
		    if (strand.equals("-")) {
			sf.setEnd(srcsize - start);
			sf.setStart(sf.getEnd() - len);
		    }

		    sf.setAlignString(aln);

		    out.put(horg,sf);
		}

		return out;
	    }

	}
	return null;
    }

    public String print() {
	return "";
    }
    public static String print(SequenceI[] s) {
    StringBuffer out = new StringBuffer("");

    int max = 0;
    int maxid = 0;

    int i = 0;

    while (i < s.length && s[i] != null) {
      String tmp = s[i].getName() + "/" + s[i].getStart()+ "-" + s[i].getEnd();

      if (s[i].getSequence().length() > max) {
        max = s[i].getSequence().length();
      }
      if (tmp.length() > maxid) {
        maxid = tmp.length();
      }
      i++;
    }

    if (maxid < 15) {
      maxid = 15;
    }

    int j = 0;
    while ( j < s.length && s[j] != null) {
        out.append(new Format("%-" + maxid + "s").form(s[j].getName() + "/" + s[j].getStart() + "-" + s[j].getEnd())).append(" ");

        out.append(s[j].getSequence()).append("\n");
      j++;
    }
    out.append("\n");

    return out.toString();
  }


    private String pad_string(char c, int len) {

	StringBuffer out = new StringBuffer();

	int i = 0;

	while (i < len) {
	    out.append(c);
	    i++;
	}

	return out.toString();
    }
}
